package cn.lysj.framework.common.validate.helper;

import cn.lysj.framework.common.validate.param.Param;
import cn.lysj.framework.common.validate.reflect.ClassUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author ww
 * @date 2018-08-22 9:43
 * @Description 该类会加载指定包下的注解,实现了可以允许开发者自定义注解
 */
public class AnnotationHelper {
    //BASE_PACKAGE 包下的所有class集合
    private static Set<Class<?>> ANNOTATION_SET;
    //初始化要加载的注解包路径
    private final static String BASE_PACKAGE = Param.ANNOTATION_URL;
    //注解Class 对应 Annotation类的map集合
    private static Map<Annotation, Class<? extends Annotation>> ANNOTATION_CLASS_SET = new HashMap<Annotation, Class<? extends Annotation>>();

    /**
     * explain 静态代码块（用于获取指定包下的class集合，存储在 ANNOTATION_SET 中）
     */
    static {
        loadAnnotation(BASE_PACKAGE);
    }

    /**
     * explain: 初始化加载所有基础校验注解class
     * @param packageName 要加载的包路径
     */
    private static void loadAnnotation(String packageName) {
        ANNOTATION_SET = ClassUtil.getClassSet(packageName);
    }


    /**
     * explain: 选择属性的校验类型（在基础包下的所有注解）注解
     * @param field 对象属性
     * @param list 用于存储Annotation
     **/
    public static void choice(Field field,Set<Annotation> list) {
        for (Class<?> clazz : ANNOTATION_SET) {
            Class<? extends Annotation> castClazz = (Class<? extends Annotation>) clazz; //interface org.yxs.medusa.annotation.Size
            if (!field.isAnnotationPresent(castClazz)) { //判断参数上的注解是属于那个注解
                continue;
            }
            Annotation annotation = field.getAnnotation(castClazz); //获取这个注解类（包括值） @org.yxs.medusa.annotation.NotNull(clazz=class org.yxs.medusa.validate.NotNullValidate, value=不能为空)
            list.add(annotation);
            ANNOTATION_CLASS_SET.put(annotation, castClazz);
        }
    }

    /**
     * explain: 选择属性的校验类型（在基础包下的所有注解）注解
     * @param field 对象属性
     * @param list 用于存储Annotation
     * @param map 忽略Annotation
     **/
    public static void choice(Field field,Set<Annotation> list, Map<String,Set<Class<? extends Annotation>>> map) {
        r:for (Class<?> clazz : ANNOTATION_SET) {
            Class<? extends Annotation> castClazz = (Class<? extends Annotation>) clazz; //interface org.yxs.medusa.annotation.Size
            Set<Class<? extends Annotation>> set = map.get(String.valueOf(field.getName()));
            if (!field.isAnnotationPresent(castClazz)) { //判断参数上的注解是属于那个注解
                continue;
            }
            if (set != null) {
                for(Class<? extends Annotation> sets : set){
                    if(sets == castClazz){
                        continue r;
                    }
                }
            }
            Annotation annotation = field.getAnnotation(castClazz); //获取这个注解类（包括值） @org.yxs.medusa.annotation.NotNull(clazz=class org.yxs.medusa.validate.NotNullValidate, value=不能为空)
            list.add(annotation);
            ANNOTATION_CLASS_SET.put(annotation, castClazz);
        }
    }

    /**
     * explain: 根据注解Annotation获取该注解的class 用于反射执行方法
     * @param annotation 自定义的注解
     **/
    public static Class<? extends Annotation> choice(Annotation annotation) {
        // 根据 annotation 取 castClazz
        return ANNOTATION_CLASS_SET.get(annotation);
    }
}
